﻿using IM.Easy.Api.Options;
using IM.Easy.Core.AppContext;
using IM.Easy.Core.Audit;
using IM.Easy.Core.Filters;
using IM.Easy.Core.SeedData;
using IM.Easy.Core.ServiceLifetime;
using Microsoft.AspNetCore.SignalR;
using Microsoft.Extensions.DependencyModel;
using Microsoft.Extensions.Options;
using SqlSugar;
using System.Collections;
using System.Reflection;

namespace IM.Easy.Api.Extensions
{
    public static class SqlSugarExtensions
    {

        public static IServiceCollection SqlSugarSetup(this IServiceCollection services)
        {
            services.AddScoped<TransactionFilter>();
            //注册上下文：AOP里面可以获取IOC对象，如果有现成框架比如Furion可以不写这一行
            services.AddHttpContextAccessor();
            var configs = ImApp.Configuration.Get<DbConnection>();
            var dbList = configs.ConnectionConfigs.Select(item =>
            {
                var configConnection = new ConnectionConfig()
                {
                    DbType = item.DbType,
                    ConnectionString = item.ConnectionString,
                    IsAutoCloseConnection = item.IsAutoCloseConnection,
                    ConfigId = item.ConfigId,
                };
                return configConnection;
            }).ToList();

            SqlSugarScope sqlSugar = new(dbList, Aop);
            services.AddSingleton<ISqlSugarClient>(sqlSugar);

            // 初始化数据库表结构及种子数据
            configs.ConnectionConfigs.ForEach(config =>
            {
                sqlSugar.InitializeDatabase(config);
            });
            return services;
        }


        /// <summary>
        /// 拦截器
        /// </summary>
        private static readonly Action<ISqlSugarClient> Aop = (db) =>
        {
            db.Aop.DataExecuting = (_, entityInfo) =>
            {
                var userId = ImApp.User?.Id ?? 0;
                switch (entityInfo.OperationType)
                {
                    //执行insert时
                    case DataFilterType.InsertByObject:
                        {
                            ////自动设置主键
                            //if (entityInfo.EntityColumnInfo.IsPrimarykey &&
                            //    entityInfo.EntityValue is Entity<long> { Id: 0 } entity)
                            //{
                            //    entity.Id = YitIdHelper.NextId();
                            //}
                            //如果当前实体继承ICreatedTime就设置创建时间

                            if (entityInfo.EntityValue is ICreatedBy createdBy)
                            {
                                createdBy.CreatedBy = userId;
                            }
                            if (entityInfo.EntityValue is ICreatedAt createdAt)
                            {
                                createdAt.CreatedAt = DateTime.Now;
                            }
                            if (entityInfo.EntityValue is IUpdatedAt updatedAt)
                            {
                                updatedAt.UpdatedAt = DateTime.Now;
                            }
                            if (entityInfo.EntityValue is IUpdatedBy updatedBy)
                            {
                                updatedBy.UpdatedBy = userId;
                            }

                            break;
                        }
                    case DataFilterType.UpdateByObject:
                        {
                            //if (entityInfo.EntityValue is IUpdated updateEntity)
                            //{
                            //    updateEntity.UpdatedAt = DateTime.Now;
                            //    updateEntity.UpdatedBy = userId;
                            //}
                            //if (entityInfo.EntityValue is ICreated insertEntity)
                            //{
                            //    if (entityInfo.EntityColumnInfo.PropertyName == nameof(insertEntity.CreatedAt))
                            //        entityInfo.EntityColumnInfo.IsOnlyIgnoreUpdate = true;
                            //    if (entityInfo.EntityColumnInfo.PropertyName == nameof(insertEntity.CreatedBy))
                            //        entityInfo.EntityColumnInfo.IsOnlyIgnoreUpdate = true;
                            //}
                            if (entityInfo.EntityValue is IUpdatedAt updatedAt)
                            {
                                updatedAt.UpdatedAt = DateTime.Now;
                            }
                            if (entityInfo.EntityValue is IUpdatedBy updatedBy)
                            {
                                updatedBy.UpdatedBy = userId;
                            }
                            if (entityInfo.EntityValue is ICreatedAt && entityInfo.PropertyName == nameof(ICreatedAt.CreatedAt))
                            {
                                entityInfo.EntityColumnInfo.IsOnlyIgnoreUpdate = true;
                            }
                            if (entityInfo.EntityValue is ICreatedBy && entityInfo.PropertyName == nameof(ICreatedBy.CreatedBy))
                            {
                                entityInfo.EntityColumnInfo.IsOnlyIgnoreUpdate = true;
                            }
                        }
                        break;
                    case DataFilterType.DeleteByObject:
                        break;
                }
            };

            // 文档地址：https://www.donet5.com/Home/Doc?typeId=1204
            db.Aop.OnLogExecuting = (sql, parameters) =>
            {
                //var originColor = Console.ForegroundColor;
                //if (sql.StartsWith("SELECT", StringComparison.OrdinalIgnoreCase))
                //    Console.ForegroundColor = ConsoleColor.Green;
                //if (sql.StartsWith("UPDATE", StringComparison.OrdinalIgnoreCase) || sql.StartsWith("INSERT", StringComparison.OrdinalIgnoreCase))
                //    Console.ForegroundColor = ConsoleColor.Yellow;
                //if (sql.StartsWith("DELETE", StringComparison.OrdinalIgnoreCase))
                //    Console.ForegroundColor = ConsoleColor.Red;
                //Console.WriteLine("【" + DateTime.Now + "——执行SQL】\r\n" + UtilMethods.GetSqlString(db.CurrentConnectionConfig.DbType, sql, parameters) + "\r\n");
                //Console.ForegroundColor = originColor;
                //App.PrintToMiniProfiler("SqlSugar", "Info", sql + "\r\n" + db.Utilities.SerializeObject(parameters.ToDictionary(it => it.ParameterName, it => it.Value)));
            };
            db.Aop.OnError = ex =>
            {
                if (ex.Parametres == null) return;
                var originColor = Console.ForegroundColor;
                Console.ForegroundColor = ConsoleColor.DarkRed;
                var pars = db.Utilities.SerializeObject(((SugarParameter[])ex.Parametres).ToDictionary(it => it.ParameterName, it => it.Value));
                Console.WriteLine("【" + DateTime.Now + "——错误SQL】\r\n" + UtilMethods.GetSqlString(db.CurrentConnectionConfig.DbType, ex.Sql, (SugarParameter[])ex.Parametres) + "\r\n");
                Console.ForegroundColor = originColor;
                //App.PrintToMiniProfiler("SqlSugar", "Error", $"{ex.Message}{Environment.NewLine}{ex.Sql}{pars}{Environment.NewLine}");
            };

            db.CurrentConnectionConfig.ConfigureExternalServices = new ConfigureExternalServices()
            {
                EntityService = (c, p) =>
                {
                    if (p.IsPrimarykey == false && new NullabilityInfoContext().Create(c).WriteState is NullabilityState.Nullable)
                    {
                        p.IsNullable = true;
                    }
                }
            };


            //配置逻辑删除过滤器（查询数据时过滤掉已被标记删除的数据）
            //db.QueryFilter.AddTableFilter<ISoftDelete>(it => it.DeleteMark == false);
        };

        /// <summary>
        /// 初始化数据库
        /// </summary>
        /// <param name="db"></param>
        /// <param name="config"></param>
        private static void InitDatabase(this DbConnectionConfig config, ISqlSugarClient db)
        {
            var assemblies = new List<Assembly>();

            // 通过 DependencyContext 获取当前项目和引用项目的所有依赖程序集
            var dependencies = DependencyContext.Default.RuntimeLibraries;
            foreach (var library in dependencies)
            {
                // 加载引用的外部程序集
                if (library.Type == "project" || library.Type == "assembly")
                {
                    try
                    {
                        assemblies.Add(Assembly.Load(new AssemblyName(library.Name)));
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine($"无法加载程序集 {library.Name}: {ex.Message}");
                    }
                }
            }

            // 获取所有种子数据类型
            var seedTypes = assemblies.SelectMany(a => a.GetTypes())
                             .Where(t => t.IsClass && !t.IsAbstract && !t.IsInterface)
                             .Where(t => t.GetInterfaces().Any(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(ISqlSugarSeed<>)))
                             .ToList();


            foreach (var seedType in seedTypes)
            {
                var entityType = seedType.GetInterfaces()
                                        .First(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(ISqlSugarSeed<>))
                                        .GetGenericArguments().First();

                var instance = Activator.CreateInstance(seedType);
                // 获取 GetSeedData 方法并执行
                var seedData = seedType.GetMethod("GetSeedData")?.Invoke(instance, null) as IEnumerable;
                // 如果种子数据为空，继续下一个类型
                if (seedData == null) continue;

                // 将种子数据转换为 object 列表
                var seedList = seedData.Cast<object>().ToList();

                var entityInfo = db.EntityMaintenance.GetEntityInfo(entityType);
                if (entityInfo.Columns.Any(u => u.IsPrimarykey))
                {
                    // 只做插入操作
                    var storage = db.StorageableByObject(seedList).ToStorage();

                    storage.AsInsertable.ExecuteCommand();
                }
                else
                {
                    // 无主键则只进行插入
                    if (!db.Queryable(entityInfo.DbTableName, entityInfo.DbTableName).Any())
                        db.InsertableByObject(seedList).ExecuteCommand();
                }
            }

        }

        public static void InitializeDatabase(this SqlSugarScope db, DbConnectionConfig config)
        {
            config ??= new DbConnectionConfig();

            if (config.DbSettings.EnableInitDb)
            {
                db.DbMaintenance.CreateDatabase();
            }

            if (config.TableSettings.EnableInitTable)
            {
                db.CodeFirst.InitTables(GetEntityTypes());
            }

            var seedMode = !config.SeedSettings.EnableInitSeed ? SeedMode.None : SeedMode.WhenEmpty;
            SqlSugarSeedHelper.RunSeeds(db, seedMode);
        }

        private static Type[] GetEntityTypes()
        {
            var assemblies = new List<Assembly>();

            // 通过 DependencyContext 获取当前项目和引用项目的所有依赖程序集
            var dependencies = DependencyContext.Default.RuntimeLibraries;
            foreach (var library in dependencies)
            {
                // 加载引用的外部程序集
                if (library.Type == "project" || library.Type == "assembly")
                {
                    try
                    {
                        assemblies.Add(Assembly.Load(new AssemblyName(library.Name)));
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine($"无法加载程序集 {library.Name}: {ex.Message}");
                    }
                }
            }

            // 获取所有的表
            var entityTypes = assemblies.SelectMany(a => a.GetTypes())
                             .Where(t => t.GetCustomAttributes<SugarTable>().Any())
                             .ToArray();
            return entityTypes;
        }
    }
}
